package com.ssh.dao.baseDao.baseDaoImpl;

import com.ssh.dao.baseDao.BaseDao;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.List;

/*************************************************************************************************************************
 *                                                         BaseDaoImpl                                                   *
 *                                                 封装(hibernate)通用方法的类                                           *
 *                                                其他类只要extends该类即可使用                                          *
 ************************************************************************************************************************/
public class BaseDaoImpl<T> implements BaseDao<T> {

    @Autowired
    protected SessionFactory sessionFactory;

    /**********************************************************************
     *                        Start:  findById方法                        *
     *                        参数：Class类名 ，String id                 *
     *                        功能：通过id获取该类的对象                  *
     *                        返回：参数类的对象（一般唯一）              *
     *********************************************************************/
    @Override
    public T findById(Class<T> entityClazz, Serializable id) {
        return sessionFactory.getCurrentSession().get(entityClazz, id);
    }
    //-------------------------End:  findById方法------------------------//





    /**********************************************************************
     *                        Start:  save方法                            *
     *                        参数：某类对象(唯一一个对象)                *
     *                        功能：将对象保存到该类对应的表内            *
     *                        返回：可无                                  *
     *********************************************************************/
    @Override
    public Serializable save(T entity) {
        return sessionFactory.getCurrentSession().save(entity);
    }
    //-------------------------End:  save方法----------------------------//





    /**********************************************************************
     *                        Start:  update方法                          *
     *                        参数：某类对象(唯一一个对象)                *
     *                        功能：如果对象id在表中不存在，那么保存      *
     *                              如果对象id在表中存在，那么更新        *
     *                        返回：无                                    *
     *********************************************************************/
    @Override
    public void update(T entity) {
        sessionFactory.getCurrentSession().saveOrUpdate(entity);
    }
    //-------------------------End:  update方法---------------------------//





    /**********************************************************************
     *                        Start:  deleteByObj方法                     *
     *                        参数：某类对象(唯一一个对象)                *
     *                        功能：在该对象对应的表中删除该对象记录      *
     *                        返回：无                                    *
     *********************************************************************/
    @Override
    public void deleteByObj(T entity) {
        sessionFactory.getCurrentSession().delete(entity);
    }
    //-------------------------End:  deleteByObj方法----------------------//





    /**********************************************************************
     *                        Start:  deleteById方法                      *
     *                        参数：Class类名 ，String id                 *
     *                        功能：根据Id在该类对应的表中删除该id的记录  *
     *                        返回：true or false                         *
     *********************************************************************/
    @Override
    @SuppressWarnings("unchecked")
    public boolean deleteById(Class<T> entityClazz, Serializable id) {
        String hql = "delete " + entityClazz.getSimpleName() + " en where en.id = ?0";
        Query<T> query = sessionFactory.getCurrentSession()
                .createQuery(hql)
                .setParameter("0", id);
        return (query.executeUpdate() > 0);
    }
    //-------------------------End:  deleteById方法-----------------------//





    /**********************************************************************
     *                        Start:  findAll方法                         *
     *                        参数：Class类名                             *
     *                        功能：返回该类名对应表的所有对象集合        *
     *                        返回：对象集合                              *
     *********************************************************************/
    @Override
    public List<T> findAll(Class<T> entityClazz) {
        String hql = "select en from " + entityClazz.getSimpleName() + " en";
        return sessionFactory.getCurrentSession().createQuery(hql).list();
    }
    //-------------------------End:  findAll方法--------------------------//





    /**********************************************************************
     *                        Start:  findCount方法                       *
     *                        参数：Class类名                             *
     *                        功能：返回该类名对应表的所有记录的总数      *
     *                        返回：long                                  *
     *********************************************************************/
    @Override
    public long findCount(Class<T> entityClazz) {
        String  hql  = "select count(*) from " + entityClazz.getSimpleName();
        List<T> list = findAllByHql(hql);
        if (list != null && list.size() == 1) {
            return (Long) list.get(0);
        }
        return 0;
    }
    //-------------------------End:  findCount方法------------------------//


    /**
     * **************************************************** 下面方法 主要和hql语句有关 ********************************************************
     */


    /**********************************************************************
     *                        Start:  findAllByHql方法                    *
     *                        参数：String hql语句                        *
     *                        功能：返回该hql查出来的所有对象集合         *
     *                        返回：对象集合                              *
     *                        注意： Hql 直接写类名，不需要写路径         *
     *********************************************************************/
    @Override
    public List<T> findAllByHql(String hql) {
        return sessionFactory.getCurrentSession()
                .createQuery(hql)
                .list();
    }
    //-------------------------End:  findAllByHql方法---------------------//





    /**********************************************************************
     *                        Start:  findByHql方法                       *
     *                        参数：String hql语句  ，参数集合            *
     *                        功能：返回该hql根据参数条件查出来的         *
     *                              所有对象集合                          *
     *                        返回：对象集合                              *
     *                                                                    *
     *                        注意：Hql语句中  ？后面跟数字 0,1,2,3...    *
     *                              Hql直接写类名，不需要写路径           *
     *********************************************************************/
    @Override
    public List<T> findByHql(String hql, Object[] params) {
        Query<T> query = sessionFactory.getCurrentSession().createQuery(hql);

        for (int i=0, len=params.length; i<len; i++) {
            query.setParameter(i + "", params[i]);
        }
        return query.list();
    }
    //-------------------------End:  findByHql方法-----------------------//








    /**
     * **************************************************** 下面方法 暂时没深入了解 ********************************************************
     */

    /**
     * 使用hql 语句进行分页查询操作
     * @param hql       需要查询的hql语句
     * @param pageNo    查询第pageNo页的记录
     * @param pageSize  每页需要显示的记录数
     * @return          当前页的所有记录
     */
    @SuppressWarnings("unchecked")
    protected List<T> findByPage(String hql, int pageNo, int pageSize) {
        Query<T> query = sessionFactory.getCurrentSession().createQuery(hql);
        return query.setFirstResult((pageNo-1) * pageSize)
                .setMaxResults(pageSize)
                .list();
    }

    /**
     * 使用hql 语句进行分页查询操作
     * @param hql       需要查询的hql语句
     * @param pageNo    查询第pageNo页的记录
     * @param pageSize  每页需要显示的记录数
     * @param params    如果hql带占位符参数，params用于传入占位符参数
     * @return          当前页的所有记录
     */
    @SuppressWarnings("unchecked")
    protected List<T> findByPage(String hql , int pageNo, int pageSize, Object... params) {
        Query<T> query = sessionFactory.getCurrentSession().createQuery(hql);
        for (int i=0, len=params.length; i<len; i++) {
            query.setParameter(i + "", params[i]);
        }
        return query.setFirstResult((pageNo - 1) + pageSize)
                .setMaxResults(pageSize)
                .list();
    }
}
